﻿/*******************************************************************/
/*    Copyright (c) 2022-2024 by GME Team.                         */
/*    All rights reserved.                                         */
/*******************************************************************/
/**
 * @file   ofstapi.cpp
 * @brief  实现ofstapi
 */
#include "acis/include/ofstapi.hxx"

#include <iostream>
#include <set>
#include <string>
#include <vector>

#include "acis/gme/kernel/gme_spline.hxx"
#include "acis/include/acistol.hxx"
#include "acis/include/off_spl.hxx"
#include "acis/include/add_pcu.hxx"
#include "acis/include/api.err"
#include "acis/include/bnd_crv.hxx"
#include "acis/include/check.hxx"
#include "acis/include/ckoutcom.hxx"
#include "acis/include/coedge.hxx"
#include "acis/include/cstrapi.hxx"
#include "acis/include/curdef.hxx"
#include "acis/include/curve.hxx"
#include "acis/include/edge.hxx"
#include "acis/include/ellipse.hxx"
#include "acis/include/errorbase.hxx"
#include "acis/include/exchg_funcs.hxx"
#include "acis/include/geom_utl.hxx"
#include "acis/include/geometry.hxx"
#include "acis/include/get_top.hxx"
#include "acis/include/getowner.hxx"
#include "acis/include/heldef.hxx"
#include "acis/include/hlc_wire_wrap.err"
#include "acis/include/intcucu.hxx"
#include "acis/include/intdef.hxx"
#include "acis/include/intrapi.hxx"
#include "acis/include/intsfsf.hxx"
#include "acis/include/kernapi.hxx"
#include "acis/include/law_base.hxx"
#include "acis/include/loop.hxx"
#include "acis/include/main_law.hxx"
#include "acis/include/offset_api.err"
#include "acis/include/ofstapi_utils.hxx"
#include "acis/include/plane.hxx"
#include "acis/include/point.hxx"
#include "acis/include/sample_edges.hxx"
#include "acis/include/sfsfint.hxx"
#include "acis/include/sp3crtn.hxx"
#include "acis/include/spline.hxx"
#include "acis/include/sps3srtn.hxx"
#include "acis/include/straight.hxx"
#include "acis/include/surface.hxx"
#include "acis/include/transf.hxx"
#include "acis/include/transfrm.hxx"
#include "acis/include/vertex.hxx"
#include "acis/include/wire_offset_options.hxx"
#include "acis/include/cstrapi.hxx"
#include "acis/include/cone.hxx"
#include "acis/include/sphere.hxx"
#include "acis/include/torus.hxx"

outcome gme_api_offset_face_edge(COEDGE const* given_coedge, double offset_distance, EDGE*& resulting_offset_edge, offset_face_edge_opts* opts, AcisOptions* ao) {
    API_BEGIN
    if(given_coedge == nullptr) {
        sys_error(NULL_COEDGE);
    } else {
        // 检查edge的curve的类型
        int ofst_type = given_coedge->edge()->geometry()->equation().type();
        // straight类型的coedge偏移
        if(ofst_type == straight_type) {
            gme_api_offset_face_edge_straight(given_coedge, offset_distance, resulting_offset_edge);
        }
        // ellipse类型的coedge偏移
        if(ofst_type == ellipse_type) {
            // 是否能够按照ellipse偏移
            bool common_ellipse = gme_api_offset_face_edge_ellipse_detect(given_coedge, offset_distance, resulting_offset_edge);
            if(!common_ellipse) {
                ofst_type = intcurve_type;
            } else {
                gme_api_offset_face_edge_ellipse(given_coedge, offset_distance, resulting_offset_edge);
            }
        }
        // 目前intcurve的偏置方法采用对intcurve进行点采样，分别计算偏置后的点的位置后，进行样条插值拟合，得到对应的偏置曲线
        // helix参照ACIS的方法，缺省归纳为intcurve类型偏移
        if(ofst_type == intcurve_type || ofst_type == helix_type) {
            // 计算是否会产生自交，参照ACIS如果自交放弃偏移结果
            if(gme_api_offset_face_edge_selfinter_detect(given_coedge, offset_distance)) {
                resulting_offset_edge = nullptr;
            } else {
                gme_api_offset_face_edge_intcurve(given_coedge, offset_distance, resulting_offset_edge);
            }
        }
    }
    API_END
    return result;
}

/**
 * @brief gme_api_offset_face_loop，对单个FACE上的所有构成FACE的LOOP进行偏移，构造偏移后的LOOP组成的FACE，并以BODY拓扑结构返回
 * 注：接口仅支持负向偏置(同ACIS)，正向偏置不会像ACIS一样返回空值，但所得到的结果会呈现意想不到的结果，参照使用场景决定是否在正向距离时返回空值。
 * @param iFace 待偏置的一个或多个Loop所在的FACE
 * @param offset_dist 偏置距离
 * @param outbody 偏置结果，以BODY形式返回
 * @param ao ACIS选项
 */

outcome gme_api_offset_face_loops(FACE* iFace, double offset_dist, BODY*& outbody, AcisOptions* ao) {
    API_BEGIN
    // 鲁棒性
    if(iFace == nullptr) {
        sys_error(NULL_FACE);
    }
    if(is_zero(offset_dist)) {
        sys_error(ZERO_DISTANCE);
    }
    // repair_type:输入loop的修复方式，0自交修复，1开裂修复
    bool repair_type = true;
    ENTITY_LIST loops_list, coedges_list;
    check_outcome(api_get_loops(iFace, loops_list));
    LOOP* temp_loop = nullptr;
    std::vector<LOOP*> ofst_loops;
    // 遍历处理iFace中的所有loop
    while(temp_loop = (LOOP*)loops_list.next()) {
        std::vector<EDGE*> loop_ofst_edges;
        // 以coedge为单位做偏移处理
        gme_api_offset_face_loops_coedges(temp_loop, offset_dist, loop_ofst_edges);

        // 检测+修复局部自交
        for(auto iter = loop_ofst_edges.begin(); iter < loop_ofst_edges.end(); iter++) {
            curve_curve_int* edge_selfints = nullptr;
            // 目前检测偏移结果方法为求交模块的线自交接口
            check_outcome(api_ed_self_inters(*iter, edge_selfints));
            EDGE* origin_edge = *iter;
            // flag判断是否是第一次的origin_edge
            logical first_origin_edge = 0;
            // 如果是正常交点则不修复
            while(edge_selfints != nullptr && !gme_offset_is_normal_intersect(*iter, edge_selfints)) {
                EDGE* divide_edge = gme_offset_del_selfint_edge_loop(origin_edge, edge_selfints->int_point);
                // 将删掉后产生的边加入loop_ofst_edges
                if(edge_selfints->next == nullptr) {
                    iter = loop_ofst_edges.insert(iter + 1, divide_edge);

                } else {
                    if(!first_origin_edge) {
                        first_origin_edge = 1;
                    } else {
                        iter = loop_ofst_edges.insert(iter + 1, origin_edge);
                    }
                }
                // 如果还存在自交点则继续分割
                edge_selfints = edge_selfints->next;
                origin_edge = divide_edge;
            }
        }
        // 检测全局自交并修复
        int loop_ofst_edges_count = loop_ofst_edges.size();
        if(loop_ofst_edges_count > 1) {
            for(int i = 0; i < loop_ofst_edges_count; i++) {
                curve_curve_int* two_edges_intersect = nullptr;
                EDGE* edge1 = nullptr;
                EDGE* edge2 = nullptr;
                if(i < loop_ofst_edges_count - 1) {
                    edge1 = loop_ofst_edges[i];
                    edge2 = loop_ofst_edges[i + 1];
                } else {
                    edge1 = loop_ofst_edges[i];
                    edge2 = loop_ofst_edges[0];
                }
                check_outcome(api_inter_ed_ed(edge1, edge2, two_edges_intersect));
                // 如果相邻两条偏移结果存在相交则修复（默认不会产生新的边）
                // @TODO:需要加判定条件，如果两条边仅仅一点重合，则不会进行修复
                if(two_edges_intersect != nullptr && two_edges_intersect) {
                    repair_type = false;
                    gme_offset_global_intersect_repair(edge1, edge2, two_edges_intersect->int_point);
                }
            }
        }
        // 检测是不是开裂
        // 上面自交修复完后点与edge数量仍对不上则有开裂，若无自交则不会进行修复
        ENTITY_LIST now_vertex_count;
        now_vertex_count.init();
        for(EDGE* edge: loop_ofst_edges) {  // 唯一性检查
            now_vertex_count.gme_add(edge->start(), TRUE);
            now_vertex_count.gme_add(edge->end(), TRUE);
        }
        if(repair_type && !(now_vertex_count.count() == loop_ofst_edges.size())) {
            // 修复开裂：不能通用natrual，偏置后的结果都是插值曲线，不能用cur求交，求交无结果，只能arc或corver，从acis表现来看是arc
            loop_ofst_edges_count = loop_ofst_edges.size();
            std::vector<EDGE*> temp_loop_ofst_edges;
            for(int i = 0; i < loop_ofst_edges_count; i++) {
                curve_curve_int* two_edges_intersect = nullptr;
                EDGE* edge1 = nullptr;
                EDGE* edge2 = nullptr;
                if(i < loop_ofst_edges_count - 1) {
                    edge1 = loop_ofst_edges[i];
                    edge2 = loop_ofst_edges[i + 1];
                } else {
                    edge1 = loop_ofst_edges[i];
                    edge2 = loop_ofst_edges[0];
                }
                VERTEX* startv = edge1->end();
                VERTEX* endv = edge2->start();
                EDGE* fixed_arc = gme_offset_repair_arc_proj(startv, endv, offset_dist, iFace->geometry()->equation());
                temp_loop_ofst_edges.emplace_back(edge1);
                temp_loop_ofst_edges.emplace_back(fixed_arc);
            }
            auto temp_ptr = loop_ofst_edges;
            loop_ofst_edges = temp_loop_ofst_edges;
            temp_loop_ofst_edges = temp_ptr;
        }
        // 构建新的loop
        LOOP* ofst_loop = gme_offset_edges_to_loop(loop_ofst_edges, temp_loop->start()->sense());
        // 将新的loop加入到ofst_loops
        ofst_loops.emplace_back(ofst_loop);
    }
    int loop_nums = ofst_loops.size();
    if(loop_nums > 1) {
        for(int i = 0; i < loop_nums - 1; i++) {
            ofst_loops[i]->set_next(ofst_loops[(i + 1) % loop_nums]);
        }
    }
    ENTITY* res_surface = nullptr;
    check_outcome(api_deep_down_copy_entity(iFace->geometry(), res_surface));
    FACE* res_face = ACIS_NEW FACE("gme", ofst_loops[0], nullptr, (SURFACE*)res_surface, iFace->sense());
    // 添加pcurve
    ENTITY_LIST coed_add_pcur;
    check_outcome(api_get_coedges(res_face, coed_add_pcur));
    for(int i = 0; i < coed_add_pcur.count(); i++) {
        sg_add_pcurve_to_coedge((COEDGE*)coed_add_pcur[i]);
    }
    outbody = ACIS_NEW BODY(ACIS_NEW LUMP(ACIS_NEW SHELL(res_face, nullptr, nullptr), nullptr));

    API_END
    return result;
}

/**
 * @brief 平面上的Wire的偏置操作，使用wire_offset_options输入偏置条件接口，其他接口功能被覆盖，ACIS逐步弃用中，可实现平面内的等距偏置与straight类型wire的非等距偏置
 * @return
 * @param iGivenWire 给出的待偏置的wire
 * @param iOptons 偏置选项，使用时平面法向量与偏置距离非空
 * @param oOffsetWire 得到的偏置结果
 * @param ao
 */
outcome gme_api_offset_planar_wire(BODY* iGivenWire, wire_offset_options* iOptons, BODY*& oOffsetWire, AcisOptions* ao) {
    API_BEGIN

    // 获取wirebody的单个wire列表
    ENTITY_LIST wire_list;
    WIRE* single_wire = nullptr;
    wire_list.init();
    check_outcome(api_get_wires(iGivenWire, wire_list));
    // 存储每个偏置后的wire
    std::vector<BODY*> new_wire_bodys;
    while(single_wire = (WIRE*)wire_list.next()) {
        ENTITY_LIST vertex_list, coedge_list, coedge_done;
        ENTITY_LIST check_coedges;
        ENTITY_LIST swire_coedges;
        check_outcome(api_get_coedges(single_wire, swire_coedges));
        int swire_conum = swire_coedges.count();
        std::vector<EDGE*> offset_edges(swire_conum, nullptr);
        std::vector<EDGE*> res_edges;
        check_outcome(api_get_vertices(single_wire, vertex_list));
        VERTEX* tempv = nullptr;
        // 以顶点为间隙修复单位
        // 如果一个点上超过三条edge存在，则只会对前两条进行操作（acis会直接将第三条删掉，只留两个操作）
        while(tempv = (VERTEX*)vertex_list.next()) {
            ENTITY_LIST vertex_coedges;
            check_outcome(api_get_coedges(tempv, vertex_coedges));
            int vertex_cnum = vertex_coedges.count();
            // 仅有一条边
            if(vertex_cnum == 1 && vertex_list.count() <= 2) {
                EDGE* new_temp_edge = nullptr;
                check_outcome(gme_api_offset_planar_wire_edges(tempv->edge()->coedge(), iOptons, new_temp_edge));
                res_edges.emplace_back(new_temp_edge);
                break;
            }
            // G0间断点的处理，以vertex视作间断点
            // add第二个参数ture时开启唯一性检查，存在的话返回数组下标
            if(vertex_cnum == 2) {
                // 获取该间断点对应的两侧的偏移edge
                EDGE* temp_start_edge = nullptr;
                EDGE* temp_end_edge = nullptr;

                // 如果选取的两条edge对应原edge在check_coedge中的顺序非顺序，则倒置两个边的输入顺序
                // TODO：目前没有对闭合wire单独写一种情况，目前暂时通过交换顺序方式部分解决闭合情况，后续应单独处理闭合情况
                if(swire_coedges.add((COEDGE*)vertex_coedges[0], true) == 0 && swire_coedges.add((COEDGE*)vertex_coedges[1], true) == swire_conum - 1) {
                    vertex_coedges.reverse();
                }

                // check_coedges用来检查当前coedge是否已经生成edges了
                // offset_edges 仅用来存储生成的edge偏置结果，与在遍历到已生成结果的coedge时返回对应的edge（偏置结果）
                // check_coedges和offset_edges的下标要严格对应
                // res_edges 存储偏置后的edge与间隙愈合所生成的edge，需要按序存储

                // add开启唯一性检查，check存在coedge则返回下标，不存在则入栈并返回下标
                int change_flag = check_coedges.count();
                bool start_save = 0, end_save = 0;
                int index = check_coedges.add((COEDGE*)vertex_coedges[0], true);
                if(change_flag != check_coedges.count()) {  // 如果不存在
                    check_outcome(gme_api_offset_planar_wire_edges((COEDGE*)vertex_coedges[0], iOptons, temp_start_edge));
                    offset_edges[index] = temp_start_edge;
                    start_save = 1;
                }
                // 用获得的index获取对应的偏置结果（edge）
                temp_start_edge = offset_edges[index];
                // 获取第二个偏置edge
                index = check_coedges.add((COEDGE*)vertex_coedges[1], true);
                if(change_flag != check_coedges.count()) {  // 如果不存在
                    check_outcome(gme_api_offset_planar_wire_edges((COEDGE*)vertex_coedges[1], iOptons, temp_end_edge));
                    offset_edges[index] = temp_end_edge;
                    end_save = 1;
                }
                temp_end_edge = offset_edges[index];

                ENTITY_LIST gap_edges;
                gap_edges.init();
                sg_gap_type new_gap;

                check_outcome(gme_api_offset_edge_gap_fill(temp_start_edge, temp_end_edge, iOptons, tempv->geometry()->coords(), gap_edges, new_gap));

                if(start_save) {
                    res_edges.emplace_back(temp_start_edge);
                }
                // 只有arc需要加入到edge列表，其他的修复直接与原曲线合并
                if(iOptons->get_gap_type() == arc || new_gap == arc) {
                    //@TODO: 将arc的修复edge按顺序加入到结果edge列表中
                    res_edges.emplace_back((EDGE*)gap_edges.first());
                }
                if(end_save) {
                    res_edges.emplace_back(temp_end_edge);
                }
            }
        }

        BODY* temp_single_wire = nullptr;
        // 如果vertex的遍历顺序错误，则会导致生成的edge顺序错误
        api_make_ewire(res_edges.size(), res_edges.data(), temp_single_wire);
        res_edges.clear();
        vertex_list.clear();
        new_wire_bodys.emplace_back(temp_single_wire);
    }
    int body_num = new_wire_bodys.size();
    // 如果new_wires_body中的body大于1个，则将这些body的lump连起来，，最后返回第一个BODY
    if(body_num > 0) {
        while(--body_num) {
            new_wire_bodys[body_num - 1]->lump()->set_next(new_wire_bodys[body_num]->lump());
            new_wire_bodys[body_num]->lump()->set_body(new_wire_bodys[body_num - 1]);
            new_wire_bodys[body_num]->set_lump(nullptr);
            api_delent(new_wire_bodys[body_num]);
        }
    }
    if(new_wire_bodys.empty()) {
        oOffsetWire = nullptr;
    } else {
        oOffsetWire = new_wire_bodys[0];
    }
    API_END
    return result;
}

// 目前仅支持偏置face的一条边界边
outcome gme_api_offset_edges_on_faces(ENTITY_LIST& coedge_chain, offset_on_faces which_faces, double offset_dist, BODY*& out_wire_body, offset_edges_options* offset_edges_opts, AcisOptions* ao) {
    API_BEGIN
    // which_face未使用，因为需求仅要求向面内偏置，如果存在选择面可以后续开发相应功能
    // offset_edges_opts已弃用
    // ao未使用
    COEDGE* temp_coedge = nullptr;
    std::vector<EDGE*> res_edges;
    while(temp_coedge = (COEDGE*)coedge_chain.next()) {
        EDGE* res_edge = nullptr;
        gme_offset_single_curve_on_face(temp_coedge, -offset_dist, res_edge);
        res_edges.emplace_back(res_edge);
    }
    check_outcome(gme_api_make_ewire(res_edges.size(), res_edges.data(), out_wire_body, NULL));
    API_END
    return result;
}

/**
 * 船体曲线沿肋骨弧长偏移
 * origin_edge 被偏置曲线
 * support_face 偏置曲线所在面
 * offset_distance 偏置距离
 * resulting_edge 偏置结果曲线
 */
outcome gme_api_offset_frame_edge(EDGE* origin_edge, FACE* support_face, double offset_distance, EDGE*& resulting_edge) {
    API_BEGIN
    // 采样点数组
    SPAposition_vector sample_points;
    // 点采样选项
    SPA_sample_edges_options sample_opt;
    double maxLen = 0.01;
    double maxTurning = M_PI / 100.0;
    sample_opt.set_as_max_len_and_turning(maxLen, maxTurning);
    // 点采样
    check_outcome(api_sample_edges(origin_edge, sample_points, &sample_opt));
    // 采样点在参数域上偏置后的位置数组
    std::vector<SPAposition> offset_sample_points;
    surf_surf_int* intsusu = nullptr;
    // 转换为参数空间点
    for(int i = 0; i < sample_points.size(); ++i) {
        // 当前采样点
        SPAposition cur_pos = sample_points[i];
        // 构造工具X平面(YZ轴构成的平面)
        plane Xplane(cur_pos, {1, 0, 0});
        // 肋骨弧长曲线
        intsusu = gme_int_surf_surf(Xplane, support_face->geometry()->equation(), SPAresabs);
        if(intsusu == nullptr) {
            break;
        }
        curve* frame_curve = intsusu->cur;
        // 计算对应参数位置
        double ofst_pos_par = frame_curve->length_param(frame_curve->param(cur_pos), offset_distance);
        SPAposition ofst_pos = frame_curve->eval_position(ofst_pos_par);
        offset_sample_points.emplace_back(ofst_pos);
    }
    if(intsusu != nullptr) {
        SPAunit_vector start_dir = normalise(origin_edge->start_deriv());
        SPAunit_vector end_dir = normalise(origin_edge->end_deriv());
        bs3_curve bs3curve_acis = bs3_curve_interp(offset_sample_points.size(), offset_sample_points.data(), start_dir, end_dir, SPAresabs);
        check_outcome(api_mk_ed_bs3_curve(bs3curve_acis, resulting_edge));
    }
    API_END
    return result;
}

// 计算给定参数下的法向量
SPAunit_vector calculate_surface_normal(SURFACE* surf, const SPApar_pos& param) {
    if(surf == nullptr) {
        // sys_error(40000);  // 偏移输入创建失败：未找到与边相对应的面
        sys_error(INVALID_OFFSET_EDGES_INPUT_HANDLE);
    }
    SPAposition pos = surf->equation().eval_position(param);
    SPAunit_vector normal = surf->equation().point_normal(pos, param);
    return normal;
}

// 对 FACE 进行采样，返回采样点的位置和参数位置对
std::vector<std::pair<SPAposition, SPApar_pos>> uniform_sample_surface_points(FACE* face, double sample_distance_u, double sample_distance_v, int& num_points_u, int& num_points_v) {
    if(face == nullptr) {
        // sys_error(40001);
        sys_error(INVALID_OFFSET_EDGES_INPUT_HANDLE);
    }
    if(!is_valid_divisor(sample_distance_u) || !is_valid_divisor(sample_distance_v)) {
        // sys_error(103007);
        sys_error(INVALID_OFFSET_EDGES_OPTIONS);
    }
    std::vector<std::pair<SPAposition, SPApar_pos>> sampled_points;
    SPApar_box uv_box = face->geometry()->equation().param_range();

    SPAinterval u_interval = uv_box.u_range();
    SPAinterval v_interval = uv_box.v_range();

    double u_range = u_interval.end_pt() - u_interval.start_pt();
    double v_range = v_interval.end_pt() - v_interval.start_pt();

    num_points_u = static_cast<int>(std::ceil(u_range / sample_distance_u)) + 1;
    num_points_v = static_cast<int>(std::ceil(v_range / sample_distance_v)) + 1;

    for(int i = 0; i < num_points_u; ++i) {
        for(int j = 0; j < num_points_v; ++j) {
            double u = u_interval.start_pt() + i * sample_distance_u;
            double v = v_interval.start_pt() + j * sample_distance_v;

            if(u > u_interval.end_pt()) u = u_interval.end_pt();
            if(v > v_interval.end_pt()) v = v_interval.end_pt();

            SPApar_pos param(u, v);
            SPAposition p = face->geometry()->equation().eval_position(param);

            sampled_points.push_back(std::make_pair(p, param));
        }
    }

    return sampled_points;
}

// 计算偏置后的采样点的位置
std::vector<std::pair<SPAposition, SPApar_pos>> calculate_offset_sample_points(const std::vector<std::pair<SPAposition, SPApar_pos>>& sampled_points, SURFACE* surf, double offset_distance) {
    if(surf == nullptr) {
        sys_error(INVALID_OFFSET_EDGES_INPUT_HANDLE);  // 面上偏移的输入句柄无效
    }

    std::vector<std::pair<SPAposition, SPApar_pos>> offset_sample_points;

    for(const auto& pos_pair: sampled_points) {
        const SPAposition& pos = pos_pair.first;
        const SPApar_pos& param = pos_pair.second;

        // 计算曲面上当前参数点的法向量
        SPAunit_vector normal = calculate_surface_normal(surf, param);

        // 根据偏置距离计算新的位置
        SPAposition offset_pos = pos + (normal * offset_distance);

        offset_sample_points.push_back(std::make_pair(offset_pos, param));
    }

    return offset_sample_points;
}

// 拟合偏置后的表面
outcome fit_offset_surface_least_squares(const std::vector<std::pair<SPAposition, SPApar_pos>>& offset_points, int num_points_u, int num_points_v, int degree_u, int degree_v, spline*& new_spline) {
    API_BEGIN

    if(offset_points.size() != num_points_u * num_points_v) {
        sys_error(INVALID_OFFSET_EDGES_OPTIONS);
    }

    std::vector<SPAposition> positions(num_points_u * num_points_v);
    std::vector<SPAvector> u_partials(num_points_u * num_points_v);
    std::vector<SPAvector> v_partials(num_points_u * num_points_v);
    std::vector<SPAvector> uv_partials(num_points_u * num_points_v);

    for(size_t i = 0; i < offset_points.size(); ++i) {
        positions[i] = offset_points[i].first;
        u_partials[i] = SPAvector(0, 0, 0);
        v_partials[i] = SPAvector(0, 0, 0);
        uv_partials[i] = SPAvector(0, 0, 0);
    }

    std::vector<double> knots_u(num_points_u + degree_u + 1);
    std::vector<double> knots_v(num_points_v + degree_v + 1);
    for(int i = 0; i <= num_points_u + degree_u; ++i) {
        knots_u[i] = static_cast<double>(i) / (num_points_u + degree_u);
    }
    for(int i = 0; i <= num_points_v + degree_v; ++i) {
        knots_v[i] = static_cast<double>(i) / (num_points_v + degree_v);
    }

    bs3_surface new_bs3_surface = bs3_surface_hermite_intp(num_points_u, num_points_v, positions.data(), u_partials.data(), v_partials.data(), uv_partials.data(), knots_u.data(), knots_v.data());

    new_spline = ACIS_NEW spline(new_bs3_surface);

    API_END
    return result;
}

/**
* @brief 比较两个点是否相同
*/
static logical gme_is_same_point(const SPAposition& pos1, const SPAposition& pos2, double tol) {
    return same_point(pos1, SPAposition{pos2.x(), pos2.y(), pos2.z()}, tol);
}
/**
 * @brief 连接两个相连的coedge
 */
static void gme_link_coedge(COEDGE* e1, COEDGE* e2) {
    if(e1->end() != e2->start()) {
        if(gme_is_same_point(e1->gme_end()->geometry()->coords(), e2->gme_start()->geometry()->coords(), SPAresabs)){
            auto* tmp = e2->gme_start();
            if(e2->start() == e2->end()) {
                e2->edge()->gme_set_end(e1->end());
                e2->edge()->gme_set_start(e1->end());
            }
            if(e2->sense() == REVERSED) {
                e2->edge()->gme_set_end(e1->end());
            } else {
                e2->edge()->gme_set_start(e1->end());
            }
            ENTITY_LIST list;
            api_get_edges(tmp, list);
            if(list.iteration_count() == 0) {
                gme_api_delent(tmp);
            }
        }
    }
    e1->gme_set_next(e2);
    e2->gme_set_previous(e1);
}
/**
 * @brief 由输入的COEDGE顺序建立次序关系
 */
static void gme_bulid_order_by_coedge_vector(std::vector<COEDGE*>& vec, bool is_reverse = false, bool is_loop = true) {
    if(vec.empty()) return;
    COEDGE* pre = nullptr;
    for(COEDGE* coedge: vec) {
        if(pre == nullptr) {
            pre = coedge;
            continue;
        }
        if(!is_reverse) {
            gme_link_coedge(pre, coedge);
        } else

        {
            gme_link_coedge(coedge, pre);
        }
        pre = coedge;
    }
    if(is_loop) {
        if(!is_reverse) {
            gme_link_coedge(vec.back(), vec.front());
        } else {
            gme_link_coedge(vec.front(), vec.back());
        }
    } else {
        if(!is_reverse) {
            vec.front()->gme_set_previous(vec.front());
            vec.back()->gme_set_next(vec.back());
        } else {
            vec.front()->gme_set_next(vec.front());
            vec.back()->gme_set_previous(vec.back());
        }
    }
}
/**
 * @brief 为除coedge外的类型建立链表关系（COEDGE需要循环链表）
 */
template <typename T> static void build_order_except_coedge(std::vector<T*>& vec) {
    if(vec.size() <= 1) return;
    T* pre = nullptr;
    for(T* entity: vec) {
        if(pre == nullptr) {
            pre = entity;
            continue;
        }
        pre->set_next(entity);
        pre = entity;
    }
}
// 曲面偏置函数
outcome gme_api_offset_face(FACE* given_face, double offset_distance, FACE*& offset_face, offset_options* pOffopts, AcisOptions* ao) {
    if(given_face == nullptr) {
        // sys_error(40000);
        sys_error(INVALID_OFFSET_EDGES_INPUT_HANDLE);
    }

    if(!is_valid_divisor(offset_distance)) {
        // sys_error(103007);
        sys_error(INVALID_OFFSET_EDGES_OPTIONS);
    }

    API_BEGIN

    // 获取原始曲面
    SURFACE* original_surface = given_face->geometry();
    std::string surface_type = original_surface->type_name();
    SPAtransf tr = get_owner_transf(given_face);
    SPAvector trans = tr.gme_translation();
    SPAtransf offset_tr = gme_translate_transf(-trans);
    ENTITY_LIST coedge_list;
    ENTITY_LIST new_coedge_list;
    ENTITY_LIST edge_list;
    ENTITY_LIST loop_list;
    get_loops(given_face, loop_list);
    get_edges(given_face, edge_list);
    int num_loops = loop_list.count();
    int num_edges = edge_list.count();
    std::vector<LOOP*> loops;
    std::vector<LOOP*> origin_loops;
    std::vector<COEDGE*> coedges;
    std::vector<EDGE*> edges;
    std::vector<EDGE*> cone_edges;
    COEDGE* coedge = NULL;
    EDGE* edge = nullptr;
    REVBIT face_sense = given_face->sense();
    std::vector<REVBIT> coedge_senses;
    while(LOOP* loop = (LOOP*)loop_list.next()) {
        origin_loops.push_back(loop);
    }
    // 根据每个LOOP的COEDGE偏移得到相应的EDGE，再利用EDGE构成COEDGE、LOOP
    for(int i = 0; i < origin_loops.size(); i++) {
        get_coedges(origin_loops[i], coedge_list);
        while(coedge = (COEDGE*)coedge_list.next()) {
            api_offset_face_edge(coedge, offset_distance, edge);
            SPAtransf edge_tr = get_owner_transf(coedge);
            edges.push_back(edge);
            coedge_senses.push_back(coedge->sense());
            if(coedge->edge()->geometry() == nullptr) {
                if(offset_distance < 0) return outcome("gme", 0);
                break;
            }
            gme_api_apply_transf(edge, offset_tr);
        }
        for(int i = 0; i < edges.size(); i++) {
            coedges.push_back(ACIS_NEW COEDGE(edges[i], coedge_senses[i], nullptr, nullptr));
        }
        gme_bulid_order_by_coedge_vector(coedges);
        loops.push_back(ACIS_NEW LOOP("gme", coedges.front(), nullptr));
        if(i == origin_loops.size() - 1) break;
        coedge_list.clear();
        edges.clear();
        coedges.clear();
        coedge_senses.clear();
    }
    while(EDGE* edge = (EDGE*)edge_list.next()) {
        cone_edges.push_back(edge);
    }
    std::map<std::string, int> surface_type_map = {
      {"plane",   1},
      {"cone",    2},
      {"sphere",  3},
      {"torus",   4},
      {"spline",  5},
    };
    int intput_surface_type = surface_type_map[surface_type];
    switch(intput_surface_type) {
        //plane类
        case 1: {
            PLANE* plne = (PLANE*)original_surface;
            SPAposition new_root;
            PLANE* geo;
            SPAposition root = plne->root_point();
            SPAunit_vector norm = plne->normal();
            SPAunit_vector new_norm = gme_normalise(norm);
            PLANE* origin_plane = (PLANE*)given_face->geometry();
            // norm = -norm;
            if(face_sense == REVERSED) {
                new_root = root - norm * offset_distance;
                geo = ACIS_NEW PLANE("gme", new_root, norm);
            } else {
                new_root = root + norm * offset_distance;
                geo = ACIS_NEW PLANE("gme", new_root, -norm);
                face_sense = REVERSED;
            }
            build_order_except_coedge(loops);
            offset_face = ACIS_NEW FACE("gme", loops.front(), nullptr, geo, given_face->sense());
            return outcome("gme", 0);
        }
        //cone类
        case 2: {
            // 获取锥面的各项参数
            CONE* con = (CONE*)original_surface;
            SPAposition center = con->root_point();
            SPAunit_vector norm = con->direction();
            SPAvector major_axis = con->major_axis();
            double major_axis_len = major_axis.len();
            if(major_axis_len + offset_distance <= 0) return outcome("gme", 0);
            SPAunit_vector unit_major_axis = gme_normalise(major_axis);
            const cone& given = (const cone&)(original_surface->equation());
            double para = given.u_param_scale;
            double cosine_angle = con->cosine_angle();
            double sine_angle = con->sine_angle();
            ellipse const& origin_bas = given.base;  // 获取base
            curve& origin_bas_curve = (curve&)origin_bas;
            EDGE *origin_bas_edge, *new_origin_bas_edge;
            api_make_edge_from_curve(&origin_bas_curve, origin_bas_edge);  // 定义base的edge

            // 获取base的各项参数
            ELLIPSE* ELL = (ELLIPSE*)(origin_bas_edge->geometry());
            SPAposition new_bas_center;
            SPAunit_vector normal = ELL->normal();
            SPAvector origin_bas_edge_axis = ELL->major_axis();

            double origin_bas_edge_ratio = ELL->radius_ratio();
            double start_param = origin_bas_edge->start_param();
            double end_param = origin_bas_edge->end_param();

            // 若sine_angle不等于0，base的center会移动
            if(gme_is_zero_mch(sine_angle))
                new_bas_center = center;
            else
                new_bas_center = center - normal * offset_distance * sine_angle;

            // 定义CONE：根据offset_distance和cosine_angle定义偏移后的base和CONE
            if(given_face->sense() == REVERSED) offset_distance = -offset_distance;
            if(origin_bas_edge_axis.len() + offset_distance * cosine_angle <= 0) return outcome("gme", 0);
            SPAvector unit_axis = gme_normalise(origin_bas_edge_axis) * (origin_bas_edge_axis.len() + offset_distance * cosine_angle);
            // api_mk_ed_ellipse(new_bas_center, normal, unit_axis, origin_bas_edge_ratio, start_param, end_param, new_origin_bas_edge);
            // ellipse const& bas = (ellipse const&)(new_origin_bas_edge->geometry()->equation());
            ellipse bas = ellipse("gme", new_bas_center, normal, unit_axis, origin_bas_edge_ratio, 0.0);

            const cone& geo = cone("gme", bas, sine_angle, cosine_angle, para);
            CONE* GEO = new CONE(geo);

            // 判断是否是圆锥面;

            int cone_curve_flag = 0;
            for(int i = 0; i < cone_edges.size(); i++) {
                CURVE* cone_curve = cone_edges[i]->geometry();
                // 只要有一条EDGE的geometry为空，就是圆锥面
                if(cone_curve == NULL) {
                    cone_curve_flag = 1;
                    break;
                }
            }
            if(cone_curve_flag == 1) {
                // 圆锥顶点偏移后会形成圆来定义顶部的COEDGE、LOOP
                SPAposition top_centr = ((const cone&)(con->equation())).get_apex();
                VERTEX* v = gme_create_vertex(top_centr);
                SPAposition new_top_center = top_centr - norm * offset_distance * sine_angle;
                EDGE* top_edge;
                api_mk_ed_ellipse(new_top_center, normal, unit_major_axis * (offset_distance * cosine_angle), origin_bas_edge_ratio, start_param, end_param, top_edge);
                COEDGE* edge_top = ACIS_NEW COEDGE("gme", top_edge, 1, nullptr, nullptr);
                edge_top->set_previous(edge_top);
                edge_top->set_next(edge_top);
                LOOP* loop_top = ACIS_NEW LOOP("gme", edge_top, nullptr);

                // 将顶点位置的COEDGE、LOOP和其他位置的COEDGE、LOOP装在一起
                std::vector<COEDGE*> new_coedges;
                std::vector<LOOP*> new_loops;
                // 圆锥面时，loop_top需要放在第二个位置
                if(num_edges == 2) {
                    for(int i = 0; i < edges.size() + 1; i++) {
                        if(i == edges.size() - 1) {
                            new_loops.push_back(loops[i]);
                            continue;
                        }
                        if(i == edges.size()) {
                            new_loops.push_back(loop_top);
                        }
                    }
                }
                // 圆锥面上开个洞，则需要放在第一个位置
                else if(num_edges > 2) {
                    for(int i = 0; i < edges.size(); i++) {
                        if(i == 0) {
                            new_loops.push_back(loop_top);
                        }
                        new_loops.push_back(loops[i]);
                    }
                }
                // 给LOOP排序
                build_order_except_coedge(new_loops);
                // 定义FACE
                offset_face = ACIS_NEW FACE("gme", new_loops.front(), nullptr, GEO, given_face->sense());
                return outcome("gme", 0);
            }

            // 给LOOP排序
            build_order_except_coedge(loops);
            offset_face = ACIS_NEW FACE("gme", loops.front(), nullptr, GEO, given_face->sense());
            return outcome("gme", 0);
        }
        //sphere类
        case 3: {
            SPHERE* sph = (SPHERE*)original_surface;
            SPAposition center = sph->centre();
            double radius = sph->radius();
            if((radius + offset_distance) <= 0) return outcome("gme", 0);
            auto* geo = ACIS_NEW SPHERE(SPAposition(0, 0, 0), radius + offset_distance);
            build_order_except_coedge(loops);
            if(loops.size() == 0) {
                offset_face = ACIS_NEW FACE("gme", nullptr, nullptr, geo, given_face->sense());
                return outcome("gme", 0);
            } else {
                offset_face = ACIS_NEW FACE("gme", loops.front(), nullptr, geo, given_face->sense());
                return outcome("gme", 0);
            }
        }
        //torus类
        case 4: {
            TORUS* tor = (TORUS*)original_surface;
            SPAposition center = tor->centre();
            double major_radius = tor->major_radius();
            double minor_radius = tor->minor_radius();
            double new_minor_radius = minor_radius + offset_distance;
            SPAunit_vector norm = tor->normal();
            if(major_radius == minor_radius) return outcome("gme", 0);
            auto* tor_geo = ACIS_NEW TORUS("gme", center, norm, major_radius, new_minor_radius);
            if(major_radius > abs(new_minor_radius) || (major_radius == abs(new_minor_radius) && major_radius > 1e10)) {
                build_order_except_coedge(loops);
                if(loops.size() == 0) {
                    offset_face = ACIS_NEW FACE("gme", nullptr, nullptr, tor_geo, given_face->sense());
                    return outcome("gme", 0);
                } else {
                    offset_face = ACIS_NEW FACE("gme", loops.front(), nullptr, tor_geo, given_face->sense());
                    return outcome("gme", 0);
                }
            } else {
                auto* ver_1 = gme_create_vertex({0, 0, sqrt((new_minor_radius) * (new_minor_radius) - (major_radius) * (major_radius))});
                auto* e_1 = ACIS_NEW EDGE("gme", ver_1, ver_1, nullptr, 0);
                VERTEX* ver_2 = nullptr;
                EDGE* e_2 = nullptr;
                if(abs(major_radius - minor_radius) < SPAresabs) {
                    ver_2 = ver_1;
                    e_2 = e_1;
                } else {
                    ver_2 = gme_create_vertex({0, 0, -sqrt((new_minor_radius) * (new_minor_radius) - (major_radius) * (major_radius))});
                    e_2 = ACIS_NEW EDGE("gme", ver_2, ver_2, nullptr, 0);
                }
                auto* ce_1 = ACIS_NEW COEDGE("gme", e_1, 0, nullptr, nullptr);
                ce_1->set_previous(ce_1);
                ce_1->gme_set_next(ce_1);
                auto* ce_2 = ACIS_NEW COEDGE("gme", e_2, 1, nullptr, nullptr);
                ce_2->set_previous(ce_2);
                ce_2->gme_set_next(ce_2);
                auto* loop_2 = ACIS_NEW LOOP("gme", ce_2, nullptr);
                auto* loop_1 = ACIS_NEW LOOP("gme", ce_1, loop_2);
                build_order_except_coedge(loops);
                if(loops.size() == 0) {
                    offset_face = ACIS_NEW FACE("gme", nullptr, nullptr, tor_geo, given_face->sense());
                    return outcome("gme", 0);
                } else {
                    offset_face = ACIS_NEW FACE("gme", loops.front(), nullptr, tor_geo, given_face->sense());
                    return outcome("gme", 0);
                }
            }
        }
        //spline类
        case 5: {
            bs3_surface orig_bs3s = ((spline&)original_surface->equation()).sur();
            bs3_surface gme_bs3s = gme_bs3_surface_from_acis(orig_bs3s);
           
            /*surface& orig_spline = (given_face->geometry())->equation_for_update();
            off_spl_sur* off_sur = ACIS_NEW off_spl_sur(orig_spline, offset_distance);
            spline off_spline = spline(off_sur);
            off_sur->make_approx_for_testing(0.01, off_spline, 0, 0, 1, 1, 0);
            result = api_make_face_from_surface(&off_spline, offset_face);*/

            //其中一种插值法偏移样条面
             const auto spline_sur = gme_bs3s->gme_sur;

             int degree_u = spline_sur->deg_u;
             int degree_v = spline_sur->deg_v;

            // 采样曲面上的点
             int num_points_u, num_points_v;
             std::vector<std::pair<SPAposition, SPApar_pos>> sampled_surface_data = uniform_sample_surface_points(given_face, 0.01, 0.01, num_points_u, num_points_v);

            // 计算偏移后的采样点
            std::vector<std::pair<SPAposition, SPApar_pos>> offset_sample_points = calculate_offset_sample_points(sampled_surface_data, original_surface, offset_distance);

            // 拟合偏移后的曲面
             spline* new_spline = nullptr;
           outcome fit_result = fit_offset_surface_least_squares(offset_sample_points, num_points_u, num_points_v, degree_u, degree_v, new_spline);
             check_outcome(fit_result);

             //创建新面
            FACE* new_face = nullptr;
             //new_face = make_face_spline((surface&)new_bs3s);
            outcome make_face_result = api_make_face_from_surface(new_spline, new_face);
            /*check_outcome(result);

            if(off_spline != nullptr) {
                ACIS_DELETE new_spline;
            }
            offset_face = new_face;
            return outcome("gme", 0);*/
        }
        default:
            sys_error(INVALID_OFFSET_EDGES_INPUT_HANDLE);
    }   
    API_END
    return result;
}
